package ruifight.member.wxController;

import java.io.BufferedReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import ruifight.member.model.AccountRecord;
import ruifight.member.model.AccountRecordExample;
import ruifight.member.model.MemberInfo;
import ruifight.member.model.MemberInfoExample;
import ruifight.member.model.ShopInfo;
import ruifight.member.model.UserInfo;
import ruifight.member.model.security.MyUserDetail;
import ruifight.member.model.vo.OrderVO;
import ruifight.member.service.AccountRecordService;
import ruifight.member.service.MemberInfoService;
import ruifight.member.service.ShopInfoService;
import ruifight.member.service.UserInfoService;
import ruifight.member.util.CommonUtil;
import ruifight.member.util.HttpClientUtil;
import ruifight.member.util.JsonUtils;
import ruifight.member.wxPay.MyWXPayConfig;
import ruifight.member.wxPay.WXPay;
import ruifight.member.wxPay.WXPayUtil;

@Controller
@RequestMapping("interface/wx/pay")
public class PayController {
	
	private static final Logger logger = LoggerFactory.getLogger(PayController.class);
	@Resource
	private AccountRecordService accountRecordService;
	@Resource
	private ShopInfoService shopInfoService;
	@Resource
	private UserInfoService userInfoService;
	@Resource
	private MemberInfoService memberInfoService;
	/**
	 * 下单
	 * @return
	 */
	@RequestMapping("/unifiedOrder")
	@ResponseBody
	public Map<String, Object> unifiedOrder(@RequestBody OrderVO unifiedOrderVO) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			MyUserDetail ud = (MyUserDetail) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
			String out_trade_no=CommonUtil.getUUID();
			AccountRecord accountRecord=new AccountRecord();
			accountRecord.setAccountCode(out_trade_no);
			accountRecord.setDraweeId(ud.getUserInfoId());
			accountRecord.setDraweeName(ud.getUserName());
			
			ShopInfo shopInfo=shopInfoService.selectByPrimaryKey(unifiedOrderVO.getShopInfoId());
			
			UserInfo userInfo=userInfoService.selectByPrimaryKey(shopInfo.getUserInfoId());
			accountRecord.setPayeeId(userInfo.getUserInfoId());
			accountRecord.setPayeeName(userInfo.getUserName());
			accountRecord.setPayeeShopId(shopInfo.getShopInfoId());
			accountRecord.setPayeeShopName(shopInfo.getShopName());
			
			accountRecord.setPayable(unifiedOrderVO.getMoney());
			accountRecord.setPayment(unifiedOrderVO.getDiscountMoney());
			
	    	BigDecimal payable = new BigDecimal(unifiedOrderVO.getMoney());
	    	BigDecimal payment = new BigDecimal(unifiedOrderVO.getDiscountMoney());
	    	BigDecimal discount = payable.subtract(payment);
			accountRecord.setDiscount(discount.toString());
			accountRecord.setAttr2(unifiedOrderVO.getFormId());
			accountRecord.setAccountRecordState(1);
			accountRecord.setCreateDate(new Date());
			map.put("out_trade_no", out_trade_no);
			String prepay_id=accountRecordService.addAccountRecord(accountRecord,unifiedOrderVO.getTotal_fee(),shopInfo.getShopType(),out_trade_no, ud.getOpenId());
			map.put("prepay_id", prepay_id);
			String nonceStr=WXPayUtil.generateNonceStr();
			String packageStr="prepay_id="+prepay_id;
			String timeStamp=(new Date().getTime()/ 1000)+"";
			map.put("timeStamp", timeStamp);
			map.put("nonceStr", nonceStr);
			map.put("package", packageStr);
			Map<String, String> signMap = new HashMap<String, String>();
			signMap.put("appId", CommonUtil.getPropertiesParam("appid"));
			signMap.put("timeStamp", timeStamp);
			signMap.put("nonceStr", nonceStr);
			signMap.put("package", packageStr);
			signMap.put("signType", "MD5");
			map.put("paySign", WXPayUtil.generateSignature(signMap,CommonUtil.getPropertiesParam("key")));
			map.put("errcode", 0);
			return map;
		} catch (Exception e) {
			logger.error("统一下单异常",e);
		}
		map.put("errcode", -1);
		return map;
	}
	/**
	 * 回调
	 * @return
	 */
	@RequestMapping("/callback")
	@ResponseBody
	public String callback(HttpServletRequest req,HttpServletResponse res) {
		Map<String, String> retMap = new HashMap<String, String>();
		try {
			StringBuilder xml = new StringBuilder();
			try(BufferedReader br=req.getReader()){
				String s=null;
				while ((s = br.readLine()) != null) {
					xml.append(s);
				}
			}catch (Exception e) {
				logger.error("回调读取异常",e);
			}
			System.out.println(xml.toString()+"-------------");
			Map<String, String> map=WXPayUtil.xmlToMap(xml.toString());
			String return_code=map.get("return_code");
			if("SUCCESS".equals(return_code)) {
				String result_code=map.get("result_code");
				if("SUCCESS".equals(result_code)) {
					String out_trade_no=map.get("out_trade_no");
					String transaction_id=map.get("transaction_id");
					AccountRecordExample accountRecordExample=new AccountRecordExample();
					accountRecordExample.createCriteria()
						.andAccountCodeEqualTo(out_trade_no)
						.andAccountRecordStateEqualTo(1);
					AccountRecord accountRecord=accountRecordService.selectOneByExample(accountRecordExample);
					if(accountRecord!=null) {
						accountRecord.setAccountRecordState(2);
						MemberInfoExample memberInfoExample=new MemberInfoExample();
						memberInfoExample.createCriteria()
							.andUserInfoIdEqualTo(accountRecord.getDraweeId())
							.andMemberStateEqualTo(1);
						MemberInfo memberInfo=memberInfoService.selectOneByExample(memberInfoExample);
						if(memberInfo!=null){
							accountRecord.setAttr1(transaction_id);
							String code=accountRecordService.finishAccountRecord(accountRecord, memberInfo.getMemberInfoId());
							try{
								SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
								String getTokenUrl=CommonUtil.getPropertiesParam("getTokenUrl");
								Map<String,String> getTokenParamMap=new HashMap<String,String>();
								getTokenParamMap.put("grant_type", CommonUtil.getPropertiesParam("grant_type"));
								getTokenParamMap.put("appid", CommonUtil.getPropertiesParam("wxgzhAppId"));
								getTokenParamMap.put("secret", CommonUtil.getPropertiesParam("wxgzhAppsecret"));
								String getTokenJson=HttpClientUtil.doGet(getTokenUrl, getTokenParamMap);
								String access_token=JsonUtils.fromJson(getTokenJson).get("access_token").asText();
								UserInfo userInfo=userInfoService.selectByPrimaryKey(accountRecord.getPayeeId());

								//发送模板消息
								String sendTemplateUrl=CommonUtil.getPropertiesParam("sendTemplateUrl");
								Map<String,Object> sendTemplateMap=new HashMap<String,Object>();
								Map<String, Object> sendTemplateDataMap = new HashMap<String, Object>();
								Map<String, String> firstMap=new HashMap<String,String>();
								firstMap.put("value", "支付成功");
								sendTemplateDataMap.put("first", firstMap);
								Map<String, String> keywordMap1=new HashMap<String,String>();
								keywordMap1.put("value", sdf.format(accountRecord.getCreateDate()));
								sendTemplateDataMap.put("keyword1", keywordMap1);
								Map<String, String> keywordMap2=new HashMap<String,String>();
								keywordMap2.put("value", accountRecord.getPayable()+"元");
								sendTemplateDataMap.put("keyword2", keywordMap2);
								sendTemplateMap.put("touser", userInfo.getAttr1());
								sendTemplateMap.put("template_id", CommonUtil.getPropertiesParam("template_id"));
								sendTemplateMap.put("data", sendTemplateDataMap);
								HttpClientUtil.doPostJson(sendTemplateUrl+"?access_token="+access_token, JsonUtils.toJson(sendTemplateMap));
							}catch(Exception e){
								logger.error("发送模板异常",e);
							}
							retMap.put("return_code", code);
							return WXPayUtil.mapToXml(retMap);
						}
					}else{
						retMap.put("return_code", "SUCCESS");
						return WXPayUtil.mapToXml(retMap);
					}
				}
			}
			retMap.put("return_code", "FAIL");
			return WXPayUtil.mapToXml(retMap);
		} catch (Exception e) {
			logger.error("回调异常",e);
		}
		return null;
	}
	/**
	 * 查询订单
	 * @return
	 */
	@RequestMapping("/orderQuery")
	@ResponseBody
	public Map<String, Object> orderQuery(@RequestBody OrderVO orderQueryVO) {
		Map<String, Object> map = new HashMap<String, Object>();
		try{
			WXPay wxPay=new WXPay(new MyWXPayConfig(),CommonUtil.getPropertiesParam("callbackUrl"),false,false);
			Map<String, String> reqData = new HashMap<String, String>();
			reqData.put("out_trade_no", orderQueryVO.getOut_trade_no());
			Map<String, String> resData=null;
			reqData=wxPay.fillRequestData(reqData);
			resData=wxPay.orderQuery(reqData);
			String return_code=resData.get("return_code");
			if("SUCCESS".equals(return_code)) {
				String result_code=resData.get("result_code");
				if("SUCCESS".equals(result_code)) {
					String trade_state=resData.get("trade_state");
					map.put("trade_state", trade_state);
					map.put("errcode", 0);
					return map;
				}
			}
		} catch (Exception e) {
			logger.error("查询订单异常",e);
		}
		map.put("errcode", -1);
		return map;
	}
	/**
	 * 完成订单
	 * @return
	 */
	@RequestMapping("/orderFinish")
	@ResponseBody
	public Map<String, Object> orderFinish(@RequestBody OrderVO orderFinishVO) {
		Map<String, Object> map = new HashMap<String, Object>();
		try{
			String out_trade_no=orderFinishVO.getOut_trade_no();
			
			AccountRecordExample accountRecordExample=new AccountRecordExample();
			accountRecordExample.createCriteria()
				.andAccountCodeEqualTo(out_trade_no)
				.andAccountRecordStateEqualTo(2);
			AccountRecord accountRecord=accountRecordService.selectOneByExample(accountRecordExample);
			if(accountRecord!=null) {
				map.put("errcode", 0);
				return map;
			}
		} catch (Exception e) {
			logger.error("发送模板消息",e);
		}
		map.put("errcode", -1);
		return map;
	}
}
